package com.fy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fy.mapper.FileInfoMapper;
import com.fy.mapper.UserMapper;
import com.fy.pojo.dto.file.RecycleFileDTO;
import com.fy.pojo.entity.FileInfo;
import com.fy.pojo.entity.User;
import com.fy.pojo.enums.FileDelFlagEnums;
import com.fy.pojo.enums.FileDelTypeEnums;
import com.fy.pojo.enums.FileFolderTypeEnums;
import com.fy.pojo.vo.user.LoginUserVO;
import com.fy.pojo.vo.file.PageResultData;
import com.fy.service.RecycleFileService;
import com.fy.utils.DateFormatter;
import com.fy.utils.RedisUtils;
import com.fy.utils.aliyunUtils.AliOssFileOperation;
import com.fy.utils.result.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RecycleFileServiceImpl implements RecycleFileService {

    @Autowired
    private FileInfoMapper fileInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AliOssFileOperation aliOssFileOperation;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 回收站文件分页查询
     *
     * @param recycleFileDTO
     * @return
     */
    @Override
    public PageResult loadRecycleList(RecycleFileDTO recycleFileDTO, LoginUserVO loginUserVO) {
        // 获取前端传来的需求页数据数
        int pageSize = recycleFileDTO.getPageSize() != null && !recycleFileDTO.getPageSize().isEmpty()
                ? Integer.parseInt(recycleFileDTO.getPageSize())
                : 15;// 默认1页有15条数据
        int pageNo = recycleFileDTO.getPageNo() != null && !recycleFileDTO.getPageNo().isEmpty()
                ? Integer.parseInt(recycleFileDTO.getPageNo())
                : 1;// 默认为第一页

        IPage<FileInfo> page = new Page<>(pageNo, pageSize);
        // 构建查询条件
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag", FileDelFlagEnums.RECYCLE.getFlag())
                .eq("user_id", userMapper.selectUserIdByName(loginUserVO.getNickName()));
        fileInfoMapper.selectPage(page, queryWrapper);

        // list1获取数据库查询的数据
        List<FileInfo> list1 = page.getRecords();

        // 创建list2来部分筛选list1的数据满足返回前端的数据格式和字段数量
        List<PageResultData> list2 = list1.stream()
                .map(record -> {
                    PageResultData pageResultData = new PageResultData();
                    BeanUtils.copyProperties(record, pageResultData);
                    pageResultData
                            .setLastUpdateTime(DateFormatter.getTimestampStringByDate(record.getLastUpdateTime()));
                    pageResultData.setRecoveryTime(DateFormatter.getTimestampStringByDate(record.getRecoveryTime()));
                    return pageResultData;
                })
                .collect(Collectors.toList());

        // 封装返回数据
        PageResult pageResult = new PageResult();
        pageResult.setTotalCount(page.getTotal());
        pageResult.setPageNo(page.getCurrent());
        pageResult.setPageSize(page.getSize());
        pageResult.setPageTotal(page.getPages());
        pageResult.setList(list2);

        log.info("一共多少页: {}", page.getPages());
        log.info("当前页码: {}", page.getCurrent());
        log.info("每页显示数: {}", page.getSize());
        log.info("一共多少条数据: {}", page.getTotal());

        return pageResult;
    }

    /**
     * 恢复删除文件
     *
     * @param fileIdList
     */
    @Override
    public void recoverFile(List<String> fileIdList) {
        // 把这些文件的回收站状态更新并且清空回收站时间，用mybatisplus
        for (String fileId : fileIdList) {
            FileInfo fileInfo = fileInfoMapper.selectById(fileId);
            fileInfo.setDelType(FileDelFlagEnums.USING.getFlag());
            fileInfo.setRecoveryTime(null);
            fileInfoMapper.updateById(fileInfo);
            log.info("恢复删除文件成功");
        }
    }

    /**
     * 永久删除回收站文件
     *
     * @param delFileList
     */
    @Override
    @Transactional
    public void delRecycleFile(List<String> delFileList, LoginUserVO loginUserVO) {
        // 1. 初始化基础数据
        LocalDateTime now = LocalDateTime.now();
        Date nowAsDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        int userId = userMapper.selectUserIdByName(loginUserVO.getNickName());

        // 2. 删除用户空间缓存
        redisUtils.delete(loginUserVO.getNickName() + "Space");

        // 使用包装类来存储累计空间
        final long[] totalReduceSpace = { 0L }; // 使用数组来存储，以便在lambda中修改

        try {
            // 4. 处理文件列表
            for (String fileId : delFileList) {
                FileInfo fileInfo = fileInfoMapper.selectById(fileId);
                if (fileInfo == null) {
                    log.warn("文件不存在，fileId: {}", fileId);
                    continue;
                }

                if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
                    // 处理文件夹
                    processFolder(fileInfo, userId, nowAsDate, totalReduceSpace);
                } else {
                    // 处理文件
                    processFile(fileInfo, userId, nowAsDate, totalReduceSpace);
                }
            }

            // 5. 更新用户空间使用量
            if (totalReduceSpace[0] > 0) {
                // 查询用户当前空间使用量
                LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
                userWrapper.eq(User::getUserId, userId);
                User user = userMapper.selectOne(userWrapper);

                if (user != null) {
                    long newUseSpace = user.getUseSpace() - totalReduceSpace[0];
                    if (newUseSpace < 0) {
                        newUseSpace = 0;
                    }
                    user.setUseSpace(newUseSpace);
                    userMapper.updateById(user);

                    log.info("用户空间更新成功, 减少空间: {}, 当前使用空间: {}", totalReduceSpace[0], newUseSpace);
                }
            }
        } catch (Exception e) {
            log.error("删除回收站文件失败", e);
            throw e;
        }
    }

    /**
     * 处理文件夹及其子内容
     */
    private void processFolder(FileInfo folder, int userId, Date nowAsDate, final long[] totalReduceSpace) {
        // 1. 更新文件夹状态为删除
        folder.setDelType(FileDelFlagEnums.DEL.getFlag());
        folder.setLastUpdateTime(nowAsDate);
        fileInfoMapper.updateById(folder);

        // 2. 获取文件夹下所有内容
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFilePid, folder.getFilePid())
                .eq(FileInfo::getUserId, userId)
                .eq(FileInfo::getDelType, FileDelFlagEnums.RECYCLE.getFlag());

        List<FileInfo> subFiles = fileInfoMapper.selectList(wrapper);

        // 3. 递归处理子内容
        for (FileInfo subFile : subFiles) {
            if (FileFolderTypeEnums.FOLDER.getType().equals(subFile.getFolderType())) {
                processFolder(subFile, userId, nowAsDate, totalReduceSpace);
            } else {
                processFile(subFile, userId, nowAsDate, totalReduceSpace);
            }
        }
    }

    /**
     * 处理单个文件
     */
    private void processFile(FileInfo file, int userId, Date nowAsDate, final long[] totalReduceSpace) {
        // 1. 检查是否有其他用户在使用此文件
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileMd5, file.getFileMd5())
                .ne(FileInfo::getUserId, userId)
                .and(w -> w.eq(FileInfo::getFileType, FileDelFlagEnums.USING.getFlag())
                        .or()
                        .eq(FileInfo::getFileType, FileDelFlagEnums.RECYCLE.getFlag()));

        long otherUsersCount = fileInfoMapper.selectCount(wrapper);

        // 2. 更新文件状态为删除
        file.setDelType(FileDelTypeEnums.DEL_HAND.getFlag());
        file.setLastUpdateTime(nowAsDate);
        file.setDelTime(new Date());
        file.setDelFlag(FileDelFlagEnums.DEL.getFlag());
        fileInfoMapper.updateById(file);

        // 3. 如果没有其他用户使用，删除阿里云文件
        if (otherUsersCount == 0 && file.getFileObjectName() != null) {
            try {
                aliOssFileOperation.deleteFile(file.getFileObjectName());
            } catch (Exception e) {
                log.error("删除阿里云文件失败: {}", file.getFileObjectName(), e);
            }
        }

        // 4. 累加需要减少的空间
        totalReduceSpace[0] += file.getFileSize();
        log.debug("文件大小累加: {}, 当前总计: {}", file.getFileSize(), totalReduceSpace[0]);
    }
}
